package front

import (
	"encoding/json"
	"fmt"
	"github.com/gin-gonic/gin"
	red "github.com/gomodule/redigo/redis"
	"github.com/juju/errors"
	"golang.org/x/crypto/bcrypt"
	"qihuang/config"
	"qihuang/db/mysql"
	"qihuang/db/redis"
	"qihuang/loger"
	"qihuang/middleware"
	"qihuang/model"
	"qihuang/protocol"
	"strconv"
	"time"
	//"reflect"
)

type UserParams struct {
	CreateTime string `json:"create_time"`
	ModifyTime string `json:"modify_time"`
	Status     int    `json:"status"`
	Username   string `json:"username"`
	Phone      string `json:"phone"`
	Password   string `json:"password"`
	Avatar     string `json:"avatar"`
	Gender     string `json:"gender"`
	City       string `json:"city"`
	Country    string `json:"country "`
	Summary    string `json:"summary"`
}

//文章详情
type UserDetails struct {
	model.Users
}

type Users struct {
}

type User struct {
	Id         int    `json:"id"`
	CreateTime string `json:"created_time"`
	ModifyTime string `json:"modify_time"`
	Username   string `json:"user_name"`
	Phone      string `json:"phone"`
	Password   string `json:"password"`
	Status     int    `json:"status"`
	Avatar     string `json:"avatar"`
	Gender     string `json:"gender"`
	City       string `json:"city"`
	Country    string `json:"country "`
	Summary    string `json:"summary"`
}

type UserSerializer struct {
	Id         int    `json:"id"`
	CreateTime string `json:"create_time"`
	ModifyTime string `json:"modify_time"`
	Status     int    `json:"status"`
	Username   string `json:"username"`
	Phone      string `json:"phone"`
	Password   string `json:"password"`
	Avatar     string `json:"avatar"`
	Gender     string `json:"gender"`
	City       string `json:"city"`
	Country    string `json:"country "`
	Summary    string `json:"summary"`
}

func BuildUser(user UserSerializer) User {
	return User{
		Id:         user.Id,
		Username:   user.Username,
		Phone:      user.Phone,
		Status:     user.Status,
		Avatar:     user.Avatar,
		CreateTime: user.CreateTime,
	}
}

//添加文章
func (c *Users) Add(params *UserParams) (resp *protocol.Resp) {
	resp = &protocol.Resp{Status: 1, Msg: "", Data: ""}
	articles := model.Users{
		CreateTime: time.Now().Format("2006-01-02 15:04:05"),
		ModifyTime: time.Now().Format("2006-01-02 15:04:05"),
		Status:     params.Status,
		Username:   params.Username,
		Phone:      params.Phone,
		Password:   params.Password,
		Avatar:     params.Avatar,
		Gender:     params.Gender,
		City:       params.City,
		Country:    params.Country,
		Summary:    params.Summary,
	}

	//articles_contents := model.ArticlesContents{
	//	ShowType: params.ShowType,
	//	Contents: params.Contents,
	//}
	//if articles_contents.GetShowTypeName() == "" {
	//	resp.Msg = "文章内容显示类型错误"
	//	return resp
	//}
	//添加articles_contents
	db := mysql.Default().GetConn()
	defer db.Close()
	// 开始事务
	tx := db.Begin()
	//添加articles
	err := db.Model(model.Users{}).Create(&articles).Error
	if err != nil {
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		resp.Msg = "系统错误"
		tx.Rollback()
		return resp
	}
	////获取插入记录的Id
	//var article_id []int
	//db.Raw("select LAST_INSERT_ID() as id").Pluck("article_id", &article_id)
	//articles_contents.ArticleId = article_id[0]
	//err = db.Create(&articles_contents).Error
	//if err != nil {
	//	loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
	//	resp.Msg = "系统错误"
	//	tx.Rollback()
	//	return resp
	//}
	//提交事务
	tx.Commit()
	resp.Status = 0
	return resp
}

func (u *Users) CurrentUser(c *gin.Context) (user model.Users) {
	authHeader := c.Request.Header.Get("Authorization")
	j := middleware.JWT{}
	tokenMap, _ := j.NewParseToken(authHeader)
	userID64 := tokenMap["ID"].(int64)
	userIDString := strconv.FormatInt(userID64, 10)
	userID, _ := strconv.Atoi(userIDString)
	user, _ = u.GetUserById(userID)
	return user
}

func (c *Users) GetUserById(userId int) (model.Users, error) {
	//articleContent := model.ArticlesContents{}
	userDetails := UserDetails{}
	redisConn := redis.RedisClient.Pool.Get()
	cacheKey := "user_" + config.Configs.RedisCacheVersion + ":" + strconv.Itoa(userId)
	if err := redisConn.Err(); err != nil {
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
	} else {
		cateCache, err := red.String(redisConn.Do("GET", cacheKey))
		if err != nil {
			loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		} else {
			if cateCache != "" {
				err := json.Unmarshal([]byte(cateCache), &userDetails)
				if err != nil {
					loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
				}
				return userDetails.Users, nil
			}
		}
	}

	db := mysql.Default().GetConn()
	defer db.Close()
	if err := db.Where("id = ?", userId).Where("status = ?", 0).First(&userDetails).Error; err != nil {
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		return model.Users{}, nil
	}
	if userDetails.Id <= 0 {
		return model.Users{}, nil
	}
	//if err := db.Where("article_id = ?", articleId).First(&articleContent).Error; err != nil {
	//	loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
	//	resp.Msg = "系统错误"
	//	return resp
	//}
	//articleDetails.Contents = articleContent.Contents
	//articleDetails.ShowType = articleContent.ShowType
	cacheData, err := json.Marshal(userDetails)
	if err == nil {
		phoneKey := "user_" + config.Configs.RedisCacheVersion + ":" + userDetails.Phone
		redisConn.Do("set", cacheKey, string(cacheData))
		redisConn.Do("set", phoneKey, string(cacheData))
		redisConn.Do("expire", cacheKey, 86400*3)
	}
	return userDetails.Users, nil
}

//分页获取文章列表mysql
func (c *Users) GetListForMysql(page int, pageSize int, fields []string) (resp *protocol.Resp) {
	resp = &protocol.Resp{Status: 1, Msg: "", Data: ""}
	db := mysql.Default().GetConn()
	defer db.Close()
	offset := (page - 1) * pageSize
	users := make([]model.Users, 0)
	db = db.Where("status = ?", 0)

	if err := db.Select(fields).Offset(offset).Limit(pageSize).Order("id desc").Find(&users).Error; err != nil {
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		resp.Msg = "系统错误"
		return resp
	}
	resp.Status = 0
	resp.Data = users
	return resp
}

//分页获取文章列表es
func (c *Users) GetListForEs(page int, pageSize int, fields []string) (resp *protocol.Resp) {
	resp = &protocol.Resp{Status: 1, Msg: "", Data: ""}
	//esclient, err := es.Default()
	//if err != nil {
	//	loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
	//	resp.Status = 1
	//	resp.Msg = "系统错误"
	//	return resp
	//}
	//esconn := esclient.GetConn()
	//ctx := context.Background()
	users := make([]model.Users, 0)

	db := mysql.Default().GetConn()
	defer db.Close()
	offSet := pageSize * (page - 1)
	if err := db.Limit(pageSize).Offset(offSet).Where("status = 0").Find(&users).Error; err != nil {
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		resp.Status = 1
		resp.Msg = "系统错误"
		return resp
	}
	//
	//query := esconn.Search().
	//	Index("myblog").
	//	Type("mb_articles").
	//	Size(page_size).
	//	From((page-1)*page_size).
	//	Sort("modify_time", false).
	//	Pretty(true)
	//boolQuery := elastic.NewBoolQuery()
	//searchQuery := boolQuery.Must(elastic.NewTermQuery("status", 1))
	//if cate_id > 0 {
	//	searchQuery = searchQuery.Filter(elastic.NewTermQuery("cate_id", cate_id))
	//}
	//query = query.Query(searchQuery)
	//result, err := query.Do(ctx)
	//if err != nil {
	//	loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
	//	resp.Status = 1
	//	resp.Msg = "系统错误"
	//	return resp
	//}
	//var typ model.Articles
	////for _, item := range result.Each(reflect.TypeOf(typ)) { //从搜索结果中取数据的方法
	//for _, item := range result.Each(reflect.TypeOf(typ)) { //从搜索结果中取数据的方法
	//	t := item.(model.Articles)
	//	t.ModifyTime = helper.DateToDateTime(t.ModifyTime)
	//	t.CreateTime = helper.DateToDateTime(t.CreateTime)
	//	articles = append(articles, t)
	//
	//}
	resp.Status = 0
	resp.Data = users
	return resp
}

//获取文章详情
func (c *Users) GetUserDetail(userId int) (resp *protocol.Resp) {
	resp = &protocol.Resp{Status: 1, Msg: "", Data: ""}
	//articleContent := model.ArticlesContents{}
	userDetails := UserDetails{}
	redisConn := redis.RedisClient.Pool.Get()
	cacheKey := "user_" + config.Configs.RedisCacheVersion + ":" + strconv.Itoa(userId)
	if err := redisConn.Err(); err != nil {
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
	} else {
		cateCache, err := red.String(redisConn.Do("GET", cacheKey))
		if err != nil {
			loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		} else {
			if cateCache != "" {
				err := json.Unmarshal([]byte(cateCache), &userDetails)
				if err != nil {
					loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
				}
				resp.Status = 0
				resp.Data = userDetails
				return resp
			}
		}
	}

	db := mysql.Default().GetConn()
	defer db.Close()
	if err := db.Where("id = ?", userId).Where("status = ?", 0).First(&userDetails).Error; err != nil {
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		resp.Msg = "用户不存在"
		return resp
	}
	if userDetails.Id <= 0 {
		resp.Msg = "用户不存在"
		return resp
	}
	//if err := db.Where("article_id = ?", articleId).First(&articleContent).Error; err != nil {
	//	loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
	//	resp.Msg = "系统错误"
	//	return resp
	//}
	resp.Status = 0
	//articleDetails.Contents = articleContent.Contents
	//articleDetails.ShowType = articleContent.ShowType
	cacheData, err := json.Marshal(userDetails)
	if err == nil {
		phoneKey := "user_" + config.Configs.RedisCacheVersion + ":" + userDetails.Phone
		redisConn.Do("set", cacheKey, string(cacheData))
		redisConn.Do("set", phoneKey, string(cacheData))
		redisConn.Do("expire", cacheKey, 86400*3)
	}
	resp.Data = userDetails
	return resp
}

// LoginReq 登录请求参数类
type LoginReq struct {
	Phone    string `json:"phone"`
	Password string `json:"password"`
}

//// 序列化
//func dumpUser(user Users) []byte {
//	dumped, _ := user.MarshalJSON()
//	return utils.CompressByte(dumped)
//}
//
//// 反序列化
//func loadUser(jsonByte []byte) User {
//	res := User{}
//	res.UnmarshalJSON(utils.DecompressByte(jsonByte))
//	return res
//}

// Register 插入用户，先检查是否存在用户，如果没有则存入
func Register(phone string, pwd string) (error, model.Users) {
	hash, err := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost) //加密处理
	if err != nil {
		fmt.Println(err)
		return err, model.Users{}
	}
	encodePWD := string(hash) // 保存在数据库的密码，虽然每次生成都不同，只需保存一份即可
	fmt.Println(encodePWD)
	//添加articles_contents
	db := mysql.Default().GetConn()
	defer db.Close()
	max := 0
	rows, err := db.Table("jk_users").Select("MAX(jk_users.family_id) AS max ").Where("deleted = ? ", 0).Rows()
	if err != nil {
		loger.Loger.Error("查询最大值报错 %v", err)
	}
	if rows.Next() {
		err := rows.Scan(&max)
		if err != nil {
			loger.Loger.Error("查询最大值报错 %v", err)
		}
	}
	user := model.Users{
		CreateTime: time.Now().Format("2006-01-02 15:04:05"),
		ModifyTime: time.Now().Format("2006-01-02 15:04:05"),
		Status:     0,
		Username:   phone,
		Phone:      phone,
		Password:   encodePWD,
		Avatar:     "https://imgx.meirijiankang.cn/avatar.png",
		Gender:     "1",
		City:       "西安",
		Country:    "中国",
		Summary:    "",
		FamilyId:   max + 1,
	}

	// 开始事务
	tx := db.Begin()
	//添加articles
	err = db.Model(model.Users{}).Create(&user).Error
	if err != nil {
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		tx.Rollback()
		return err, user
	}
	//提交事务
	tx.Commit()
	return err, user
}

// CheckUser 检查用户是否存在
func CheckUser(phone string) (model.Users, bool) {
	result := false
	redisConn := redis.RedisClient.Pool.Get()
	phoneKey := "user_" + config.Configs.RedisCacheVersion + ":" + phone
	user := model.Users{}
	if err := redisConn.Err(); err != nil {
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
	} else {
		cateCache, err := red.String(redisConn.Do("GET", phoneKey))
		if err != nil {
			loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		} else {
			if cateCache != "" {
				err := json.Unmarshal([]byte(cateCache), &user)
				if err != nil {
					loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
				}
				return user, true
			}
		}
	}
	db := mysql.Default().GetConn()
	defer db.Close()
	if err := db.Where("phone = ?", phone).Where("status = ?", 0).First(&user).Error; err != nil {
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		return user, false
	}
	if user.Id <= 0 {
		loger.Loger.Info("用户不存在")
	} else {
		result = true
	}
	return user, result
}

// UpdateUser 更新用户信息
func UpdateUser(params UserParams) (UserDetails, error) {
	db := mysql.Default().GetConn()
	defer db.Close()
	userDetails := UserDetails{}
	if err := db.Where("phone = ?", params.Phone).Where("status = ?", 0).First(&userDetails).Error; err != nil {
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		return UserDetails{}, nil
	}
	userDetails.Username = params.Username
	userDetails.City = params.City
	userDetails.Country = params.Country
	userDetails.Gender = params.Gender
	err := db.Save(&userDetails).Error
	tx := db.Begin()
	if err != nil {
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		tx.Rollback()
		return UserDetails{}, nil
	}
	//提交事务
	tx.Commit()
	return userDetails, err
}

//ResetPwd 重置密码
func ResetPwd(phone string, pwd string) error {
	db := mysql.Default().GetConn()
	defer db.Close()
	userDetails := UserDetails{}
	if err := db.Where("phone = ?", phone).Where("status = ?", 0).First(&userDetails).Error; err != nil {
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		return err
	}
	if userDetails.Id <= 0 {
		loger.Loger.Info("用户不存在")
		return nil
	}
	hash, err := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost) //加密处理
	if err != nil {
		fmt.Println(err)
		return err
	}
	encodePWD := string(hash) // 保存在数据库的密码，虽然每次生成都不同，只需保存一份即可
	fmt.Println(encodePWD)
	err = db.Model(&userDetails).UpdateColumn("password", encodePWD).Error
	tx := db.Begin()
	if err != nil {
		loger.Loger.Error(errors.ErrorStack(errors.Trace(err)))
		tx.Rollback()
		return err
	}
	//提交事务
	tx.Commit()
	return err
}
